home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / ada_gwu / adalex.c < prev    next >
C/C++ Source or Header  |  1996-01-30  |  22KB  |  807 lines

  1. /*
  2.  * Copyright (C) 1985-1992  New York University
  3.  * 
  4.  * This file is part of the Ada/Ed-C system.  See the Ada/Ed README file for
  5.  * warranty (none) and distribution info and also the GNU General Public
  6.  * License for more details.
  7.  
  8.  */
  9.  
  10. /*            Lexical scanner for ADA 
  11.  
  12. One line of text at a time is read in using getline(). Tokens are scanned
  13. for, and gettok() returns one token at a time to the parser. What is actually
  14. returned is a pointer to a structure for the parse stack capable of holding
  15. the token. No initialization is needed, as it has all been done statically
  16. (before run time).
  17. */
  18.  
  19. /* define PDEBUG to get some debug trace output */
  20.  
  21. #include "hdr.h"
  22. #include "adalex.h"
  23. #include "miscp.h"
  24. #include "errsp.h"
  25. #include "adalexp.h"
  26.  
  27. static int getline();
  28. static struct prsstack *newtoken(int, int, int, int);
  29. static int isdecimal(char);
  30. static int ishex(char);
  31. static int isletterordigit(char);
  32. static int scanidorint(char *, int *, int *, int (*func)(char), int);
  33. static void scanexp(char *, int *, int *);
  34. static int scandec(char *, int *, int *, int (*func)(char));
  35. static void checkbased(char *, int *);
  36. static void convtoupper(char *);
  37. static void nlisthash(int, int *, int *);
  38. static int newnode(char *, int, int);
  39.  
  40. /* Global variables */
  41.  
  42. int lineno = 0;                    /* Current line number in adafile */
  43. int colno;                        /* Current column number in adafile */
  44.  
  45. char *data = (char *)source_buf[0];        /* Current line of ada program */
  46. char *line = (char *)source_buf[0];        /* Pointer to character within data array */
  47. /* These are initialized so that an end of line is indicated */
  48.  
  49. char *nonprintingmsg[] = {    /* Messages for non-printing characters */
  50.     "NUL (^@)",
  51.     "SOH (^A)",
  52.     "STX (^B)",
  53.     "ETX (^C)",
  54.     "EOT (^D)",
  55.     "ENQ (^E)",
  56.     "ACK (^F)",
  57.     "BEL (^G)",
  58.     "BS (^H)",
  59.     "HT (^I)",
  60.     "LF (^J)",
  61.     "VT (^K)",
  62.     "FF (^L)",
  63.     "CR (^M)",
  64.     "SO (^N)",
  65.     "SI (^O)",
  66.     "DLE (^P)",
  67.     "DC1 (^Q)",
  68.     "DC2 (^R)",
  69.     "DC3 (^S)",
  70.     "DC4 (^T)",
  71.     "NAK (^U)",
  72.     "SYN (^V)",
  73.     "ETB (^W)",
  74.     "CAN (^X)",
  75.     "EM (^Y)",
  76.     "SUB (^Z)",
  77.     "ESC",
  78.     "FS",
  79.     "GS",
  80.     "RS",
  81.     "US"};
  82. char source_buf[NUM_LINES][MAXLINE + 1] = { '\0' }; /* Source lines buffer */
  83. int src_index = -1;        /* Index into source lines buffer */
  84.  
  85.  
  86. /* Getline: Read a line into data, returning EOF on end of file.
  87.     ^J, ^K, ^L, ^M (10-13) are all interpreted as end of line. 
  88.     Line, lineno, and colno    are set as neeeded. */
  89.  
  90. /* Note: At present, the listing of the ada source file is done after
  91.    reading the line, in getline(). Because the source file may have tabs,
  92.    in order to insure that the relative spacing of the characters in the
  93.    source file appears correctly on the screen and that underlining of
  94.    errors occurs correctly, the number of characters printed on each
  95.    line before the next source line should be a multiple of 8 (tab stops
  96.    are at 8k+1). At present we leave 5 spaces for the line number, print
  97.    a colon (:), and leave 2 more spaces before printing the source line for
  98.    a total of 8 spaces.
  99. */
  100.  
  101. /* A buffer of NUM_LINES source lines is kept for the purpose of printing
  102.    error messages. Source_buf is the buffer, src_index is the index into
  103.    the buffer for the current line.
  104. */
  105.  
  106. /*
  107. #include "d:\ed\edit.h"
  108. extern AVL_EDIT_WINDOW_PTR avl_w;
  109. AVL_LINE_PTR avl_temp;
  110.  
  111.     
  112. int AVL_GETC()
  113. {
  114.     char txt[100];
  115.     struct rccoord old;
  116.     if (avl_w -> txt_pos >= strlen(avl_w -> current_line -> line))  {
  117.         avl_w -> current_line = avl_w -> current_line -> next;
  118.         avl_w -> txt_pos = 0;
  119.         if (avl_w -> current_line == avl_w -> head)
  120.             return(EOF);
  121.         
  122.         old = _settextposition(1, 17);
  123.         sprintf(txt,"%4d", avl_w -> current_line -> line_no - 1);  
  124.         _outtext(txt);
  125.         return '\n';
  126.         }
  127.     if (avl_w -> current_line -> line [ avl_w -> txt_pos] == 1)
  128.         return EOF;
  129.     return avl_w -> current_line -> line [avl_w -> txt_pos++];
  130. }
  131.  
  132. */
  133.  
  134. static int getline()                                            /*;getline*/
  135. {
  136.     int ch, ind = 0;
  137.  
  138. /*    if (avl_w -> current_line == avl_w -> head) */
  139.     if (feof(adafile))  
  140.         return(EOF);
  141.     src_index = (src_index + 1) % NUM_LINES;
  142.     line = data = source_buf[src_index];
  143.     lineno++;
  144.     colno = 1;
  145.     for (;;) {
  146.         ch = /*  AVL_GETC(); */  getc(adafile); 
  147.         if (ch==EOF) break;
  148.         if (ch <= 13 && ch >= 10) break;
  149.         if (ind == MAXLINE) {
  150.             char msg[80];
  151.             sprintf(msg,
  152.               "Line %d exceeds maximum length, truncated to %d characters",
  153.               lineno, MAXLINE);
  154.             lexerr(lineno, 1, 1, msg);
  155.             while ((ch = getc(adafile)) != EOF && !(ch<=13 && ch>=10));
  156.             break;
  157.         }
  158.         else {
  159.             data[ind++] = ch;
  160.         }
  161.     }
  162.  
  163.     data[ind] = '\0';
  164.     if (ch == EOF && !ind)
  165.         return(EOF);
  166. #ifdef DEBUG
  167.     if (trcopt)
  168.         fprintf(errfile, "%5d:    %s\n", lineno, data);
  169.     if (termopt)
  170.         printf(         "%5d:    %s\n", lineno, data);
  171. #endif    
  172.     return(0);
  173. }
  174.  
  175. static struct prsstack *newtoken(int num, int index, int line, int col)
  176.                                                                 /*;newtoken*/
  177. {
  178.     /* Newtoken: allocate memory for a new token structure, and initialize */
  179.     /* the fields of the structure. */
  180.  
  181.     struct prsstack *tok;
  182.  
  183.     tok = PRSALLOC();
  184.     tok->symbol = num;
  185.     tok->ptr.token = TOKALLOC();
  186.     tok->ptr.token->index = index;
  187.     tok->ptr.token->span.line = line;
  188.     tok->ptr.token->span.col = col;
  189.     return(tok);
  190. }
  191.  
  192. /* Functions for passing to scanidorint */
  193.  
  194. static int isdecimal(char ch)                                    /*;isdecimal*/
  195. {
  196.     return(isdigit(ch));
  197. }
  198.  
  199. static int ishex(char ch)                                        /*;ishex*/
  200. {
  201.     return(isdigit(ch) || 'A' <= ch && ch <= 'F' || 'a' <= ch && ch <= 'f');
  202. }
  203.  
  204. static int isletterordigit(char ch)                        /*;isletterordigit*/
  205. {
  206.     return(isalpha(ch) || isdigit(ch));
  207. }
  208.  
  209. struct prsstack *gettok()                                        /*;gettok*/
  210. {
  211.     /* Gettok: Scan and return the next token in the adafile, adding the */
  212.     /* token to namelist. */
  213.  
  214.     static int nextcanbeprime = 0;    /* The next token can be a prime */
  215.     static int canbeprime;            /* The current token can be a prime */
  216.     struct prsstack *tok;            /* Token to be returned */
  217.  
  218.     while (1) {
  219.         while (1) {
  220.             while (*line == ' ' || *line == '\t') {
  221.                 colno += (*line == '\t') ? (8 - ((colno - 1) % 8)) : 1;
  222.                 line++;
  223.             }
  224.             if (!*line || *line == '-' && line[1] == '-')
  225.                 break;
  226.             canbeprime = nextcanbeprime;
  227.             nextcanbeprime = 0;
  228.  
  229.             if (isalpha(*line)) {        /* Scan identifiers */
  230.                 char id[MAXLINE + 1];
  231.                 int idind = 0, chread = 0;
  232.                 int tokind, toksym;
  233.  
  234.                 scanidorint(id, &idind, &chread, isletterordigit, 0);
  235.                 if (id[idind - 1] == '_')
  236.                     idind--;
  237.                 id[idind] = '\0';
  238.                 convtoupper(id);
  239.                 tokind = namemap(id, idind);
  240.                 toksym = MIN(tokind, ID_SYM);
  241.                 tok = newtoken(toksym, tokind, lineno, colno);
  242.                 nextcanbeprime = toksym == ID_SYM || toksym == RANGE_SYM
  243.                   || toksym == ALL_SYM;
  244.                 colno += chread;
  245.                 line += chread;
  246.                 return(tok);
  247.             }
  248.  
  249.             else if (isdigit(*line) || *line == '.' && isdigit(line[1])) {
  250.             /* Scan numeric literals */
  251.                 char num[MAXLINE + 3];
  252.                 int ind = 0, chread = 0, result;
  253.                 char ch;
  254.                 /* ind is the index into the num string */
  255.                 /* chread is the index into the line input string */
  256.  
  257.                 result = scandec(num, &ind, &chread, isdecimal);
  258.                 ch = line[chread];
  259.                 if (result == 1 && (ch == '#' || ch == ':')) {
  260.                 /* Scan for the rest of a based literal */
  261.                     num[ind++] = '#';
  262.                     chread++;
  263.                     if (!scandec(num, &ind, &chread, ishex)) {
  264.                         lexerr(lineno, colno + chread - 1, colno + chread - 1,
  265.                           "Incomplete based number");
  266.                         num[ind++] = '0';
  267.                     }
  268.                     num[ind++] = '#';
  269.                     if (line[chread] != ch) {
  270.                         if (line[chread] == '#' + ':' - ch) {
  271.                             lexerr(lineno, colno + chread, colno + chread,
  272.                               "Expect #'s or :'s in based number to match");
  273.                             chread++;
  274.                         }
  275.                         else {
  276.                             char msg[50];
  277.  
  278.                             sprintf(msg, "Expect '%c' after last digit", ch);
  279.                             lexerr(lineno, colno + chread - 1,
  280.                               colno + chread - 1, msg);
  281.                         }
  282.                     }
  283.                     else
  284.                         chread++;
  285.                     checkbased(num, &ind);
  286.                 }
  287.                 scanexp(num, &ind, &chread);
  288.                 if (isalpha(line[chread]))
  289.                     lexerr(lineno, colno, colno + chread - 1,
  290.                       "Number should be separated from adjacent identifier");
  291.                 num[ind] = '\0';
  292.                 tok = newtoken(NUMBER_SYM, namemap(num, ind), lineno, colno);
  293.                 colno += chread;
  294.                 line += chread;
  295.                 return(tok);
  296.             }
  297.  
  298.             else if (*line == '\'') {
  299.                 int err = 0;
  300.  
  301.                 if (line[1] != '\0' && line[2] == '\'' &&
  302.                     (!canbeprime || line[1] != '(')) {
  303.                 /* Scan a character literal */
  304.                     char str[4];
  305.                     int len = 3;
  306.  
  307.                     strcpy(str, "' '");
  308.                     if (!isprint(line[1]) && line[1] != ' ') {
  309.                         char msg[80];
  310.  
  311.                         sprintf(msg,
  312.   "Invalid character %s in character literal replaced by space",
  313.                           nonprintingmsg[line[1]]);
  314.                         lexerr(lineno, colno + 1, colno + 1, msg);
  315.                         len = (line[1] == '\t') ? (10 - (colno % 8)) : 2;
  316.                     }
  317.                     else
  318.                         str[1] = line[1];
  319.                     tok = newtoken(CHAR_SYM, namemap(str, 3), lineno, colno);
  320.                     colno += len;
  321.                     line += 3;
  322.                     return(tok);
  323.                 }
  324.                 else if (!canbeprime) {
  325.                 /* Possibly a single quote delimited string */
  326.                     int ind;
  327.  
  328.                     if (line[1] == '\'')
  329.                         ind = 1;
  330.                     else {
  331.                         ind = 3;
  332.                         while (line[ind]) {
  333.                             if (line[ind] == '\'') {
  334.                                 if (line[ind + 1] && line[ind + 2] == '\'') {
  335.                                     ind = -1;
  336.                                     break;
  337.                                 }
  338.                                 else {
  339.                                     if (line[ind + 1] != '\'')
  340.                                         break;
  341.                                     ind++;
  342.                                 }
  343.                             }
  344.                             ind++;
  345.                         }
  346.                     }
  347.                     if (ind > -1 && line[ind]) {
  348.                         err = 1;
  349.                         lexerr(lineno, colno, colno + ind,
  350.                           "Expect double quotes to delimit a character string");
  351.                         do
  352.                             if (line[ind] == '\'')
  353.                                 line[ind] = '"';
  354.                         while (ind--);
  355.                     }
  356.                 }
  357.                 if (!err) {     /* A prime */
  358.                     int ind = namemap("'", 1);
  359.  
  360.                     tok = newtoken(ind, ind, lineno, colno);
  361.                     colno++;
  362.                     line++;
  363.                     return(tok);
  364.                 }
  365.             }
  366.             else if (*line == '"' || *line == '%') {
  367.             /* Scan a string literal */
  368.                 int col = colno;
  369.                 int oldindex = 0, newindex = -1;
  370.                 char bracket = *line;
  371.                 char nxtchr ;
  372.                 char tmpstr[MAXLINE + 1];
  373.                 int   save_col;       /* these are maintained to restore line */
  374.                 char *save_line;   /* in case of missing string bracket */
  375.                 int   save_newindex;
  376.  
  377.                 if ( (strchr(line+1, bracket)) == 0 ) {
  378.                     char bracket_str[2];
  379.                     *bracket_str = bracket; 
  380.                     *(bracket_str + 1) = '\0';
  381.                     tok = newtoken(ERROR_SYM, namemap(bracket_str, 1),
  382.                         lineno, colno);
  383.                     line++;
  384.                     colno++;
  385.                     return(tok);
  386.                 }
  387.                 while (1) {
  388.                     save_line = line + oldindex + 1;
  389.                     save_col = col + 1;
  390.                     save_newindex = newindex + 1;
  391.                     do {
  392.                         col++;
  393.                         oldindex++;
  394.                         newindex++;
  395.                         nxtchr = line[oldindex] ;
  396.                         tmpstr[newindex] = nxtchr ;
  397.                     }
  398.                     /* test separately for bracket for use of % as delimiter */
  399.                     while (nxtchr != bracket  && IS_STRING_CHAR(nxtchr));
  400.  
  401.                     if (line[oldindex] == bracket) {
  402.                         if (line[oldindex + 1] == bracket) {
  403.                             tmpstr[newindex] = bracket ;
  404.                             oldindex++;
  405.                             col++;
  406.                         }
  407.                         else {
  408.                             tmpstr[newindex] = '\0';
  409.                             tok = newtoken(STRING_SYM, namemap(tmpstr,
  410.                               newindex), lineno, colno+1);
  411.                             colno = col + 1;
  412.                             line += oldindex + 1;
  413.                             return(tok);
  414.                         }
  415.                     }
  416.                     else if (line[oldindex] == '"') {
  417.                         oldindex++;
  418.                         lexerr(lineno, col, col,
  419.                           "% delimited string contains \", being ignored");
  420.                     }
  421.                     else if (line[oldindex] == '\0') {
  422.                         lexerr(lineno, colno, colno, "Missing string bracket");
  423.                         /* restore values of line and colno to values prior to
  424.                          * last set of string characters 
  425.                           */
  426.                         line = save_line;
  427.                         colno = save_col;
  428.                         /*  insert a closing string bracket */
  429.                         tmpstr[save_newindex] = bracket;
  430.                         tmpstr[save_newindex + 1] = '\0';
  431.                         tok = newtoken(STRING_SYM, namemap(tmpstr,
  432.                           save_newindex + 1), lineno, colno);
  433.                         return(tok);
  434.                     }
  435. /*
  436.             else if (isprint(line[oldindex]) || line[oldindex] == ' ')
  437.             tmpstr[newindex] = line[oldindex];
  438. */
  439.                     else {
  440.                         char msg[80];
  441.  
  442.                         sprintf(msg, "Invalid character %s in string deleted",
  443.                           nonprintingmsg[line[oldindex++]]);
  444.                         lexerr(lineno, col, col, msg);
  445.                         col += (line[oldindex] == '\t') ? 7 - ((col-1)%8) : -1;
  446.                     }
  447.                 }
  448.             }
  449.  
  450.             else if (ISDELIMITER(*line))    /* Scan a delimiter */
  451.             {
  452.                 int len = 1, ind;
  453.                 char str[3];
  454.  
  455.                 switch (*line) {
  456.                 case '=' :
  457.                     if (line[1] == '>')
  458.                         len = 2;
  459.                     break;
  460.                 case '*' :
  461.                     if (line[1] == '*')
  462.                         len = 2;
  463.                     break;
  464.                 case ':' :
  465.                 case '/' :
  466.                     if (line[1] == '=')
  467.                         len = 2;
  468.                     break;
  469.                 case '>' :
  470.                     if (line[1] == '=' || line[1] == '>')
  471.                         len = 2;
  472.                     break;
  473.                 case '<' :
  474.                     if (line[1] == '=' || line[1] == '<' || line[1] == '>')
  475.                         len = 2;
  476.                     break;
  477.                 case '.' :
  478.                     if (line[1] == '.')
  479.                         len = 2;
  480.                     break;
  481.                 case '!' :
  482.                     *line = '|';
  483.                     break;
  484.                 case '[' :    /* Change to a "(" */
  485.                     lexerr(lineno, colno, colno,
  486.                       "Bad character \"[\", replaced by \"(\".") ;
  487.                     line[0] = '(' ;
  488.                     break ;
  489.                 case ']' :    /* Change to a ")" */
  490.                     /* Note that this case falls through to the next one */
  491.                     lexerr(lineno, colno, colno,
  492.                       "Bad character \"]\", replaced by \")\".") ;
  493.                     line[0] = ')' ;
  494.                 case ')' :
  495.                     nextcanbeprime = 1;
  496.                     break;
  497.                 }
  498.                 strncpy(str, line, len);
  499.                 str[len] = '\0';
  500.                 ind = namemap(str, len);
  501.                 tok = newtoken(ind, ind, lineno, colno);
  502.                 colno += len;
  503.                 line += len;
  504.                 return(tok);
  505.             }
  506.  
  507.             else if (*line == '_') {    /* An error- an underline _ */
  508.                 lexerr(lineno, colno, colno, "Break character misplaced");
  509.                 colno++;
  510.                 line++;
  511.             }
  512.  
  513.             else {    /* An error- an unknown character */
  514.                 char msg[80];
  515.                 char ch[2];
  516.  
  517.                 *ch = *line;
  518.                 ch[1] = '\0';
  519.                 sprintf(msg, "Bad character in file ignored: %s",
  520.                     (isprint(*line)) ? ch : nonprintingmsg[*line]);
  521.                 lexerr(lineno, colno, colno, msg);
  522.                 if (isprint(*line))
  523.                     colno++;
  524.                 line++;
  525.             }
  526.         }
  527.         if (getline() == EOF)
  528.             return(newtoken(EOFT_SYM, EOFT_SYM, lineno, colno));
  529.     }
  530. }
  531.  
  532. static int scanidorint(char *str, int *ind, int *chread, int (*func)(char),
  533.   int ignore_break)                                            /*;scanidorint*/
  534. {
  535.     /* Scanidorint: scan for an integer or id, with allowed characters
  536.      * determined by satisfying function func. 1 returned if found, 0 if not.
  537.      */
  538.     /* ind is the index into the string str,
  539.      * chread is the index into the input string line
  540.      * func is a function to be called to determine what chars are to
  541.      * be included in the integer or identifier
  542.      */
  543.  
  544.     int hadnum = 0;
  545.  
  546.     while (1) {
  547.         if (line[*chread] == '_') {
  548.             lexerr(lineno, colno + *chread, colno + *chread,
  549.               "Break character misplaced");
  550.             (*chread)++;
  551.             continue;
  552.         }
  553.         if (!(*func)(line[*chread])) {
  554.             if (hadnum)
  555.                 lexerr(lineno, colno + *chread - 1, colno + *chread - 1,
  556.                   "Break character misplaced");
  557.             break;
  558.         }
  559.         str[(*ind)++] = line[(*chread)++];
  560.         hadnum = 1;
  561.         while ((*func)(line[*chread]))
  562.             str[(*ind)++] = line[(*chread)++];
  563.         if (line[*chread] != '_')
  564.             break;
  565.         (*chread)++;
  566.         if (!ignore_break)
  567.             str[(*ind)++] = '_';
  568.     }
  569.     return(hadnum);
  570. }
  571.  
  572. static void scanexp(char *str, int *ind, int *chread)            /*;scanexp*/
  573. {
  574.     /* Scanexp: scan for an (optional) exponent
  575.      * ind is the index into the string str,
  576.      * chread is the index into the input string line
  577.      */
  578.  
  579.     int oldchread;
  580.  
  581.     if (line[*chread] != 'E' && line[*chread] != 'e')
  582.         return;
  583.     oldchread = *chread;
  584.     str[(*ind)++] = 'E';
  585.     *chread += 1;
  586.     if (line[*chread] == '+' || line[*chread] == '-')
  587.         str[(*ind)++] = line[(*chread)++];
  588.     if (!scanidorint(str, ind, chread, isdecimal, 1)) {
  589.         lexerr(lineno, colno + oldchread, colno + *chread - 1,
  590.           "Incomplete exponent");
  591.         str[(*ind)++] = '0';
  592.     }
  593. }
  594.  
  595. static int scandec(char *str, int *ind, int *chread, int (*func)(char))
  596.                                                                 /*;scandec*/
  597. {
  598.     /* Scandec: scan for an integer followed possibly by a decimal point and 
  599.      * another integer, with digits determined by satisfying func. 1 is returned
  600.      * if an integer is found, 2 if a there was a decimal point, 0 if no digits
  601.      * found.
  602.      * ind is the index into the string str,
  603.      * chread is the index into the input string line
  604.      * func is a func indicating valid characters for numbers being scanned
  605.      */
  606.  
  607.     int stat;
  608.  
  609.     stat = scanidorint(str, ind, chread, func, 1);
  610.     if (line[*chread] == '.') {
  611.         if (line[*chread + 1] != '.') {
  612.             if (!stat) {
  613.                 lexerr(lineno, colno + *chread, colno + *chread,
  614.                   "Missing digit before decimal point");
  615.                 str[(*ind)++] = '0';
  616.             }
  617.             str[(*ind)++] = '.';
  618.             (*chread)++;
  619.             if (!scanidorint(str, ind, chread, func, 1)) {
  620.                 lexerr(lineno, colno + *chread - 1, colno + *chread - 1,
  621.                   "Missing digit after decimal point");
  622.                 str[(*ind)++] = '0';
  623.             }
  624.             return(2);
  625.         }
  626.     }
  627.     return(stat);
  628. }
  629.  
  630. static void checkbased(char *str, int *ind)/*;checkbased*/
  631. {
  632.     /* Checkbased: check the validity of a based literal */
  633.  
  634.     int base, err = 0;
  635.     char *pos;
  636.  
  637.     sscanf(str, "%d", &base);
  638.     pos = strchr(str, '#');
  639.     if (base < 2 || base > 16) {
  640.         lexerr(lineno, colno, colno + pos - str - 1,
  641.           "Base not in range 2..16");
  642.         err = 1;
  643.     }
  644.     else 
  645.         while (*++pos != '#') {
  646.             if (islower(*pos))
  647.                 *pos = toupper(*pos);
  648.             if (isdigit(*pos) && *pos - '0' >= base
  649.               || isalpha(*pos) && *pos - 'A' >= base - 10) {
  650.                 lexerr(lineno, colno + pos - str, colno + pos - str,
  651.                   "Invalid based-number digit");
  652.                 err = 1;
  653.                 break;
  654.             }
  655.         }
  656.     if (err) {
  657.         if (strchr(str, '.') == (char *)0) {
  658.             *ind = 1;
  659.             *str = '0';
  660.         }
  661.         else {
  662.             *ind = 3;
  663.             strcpy(str, "0.0");
  664.         }
  665.     }
  666. }
  667.  
  668. static void convtoupper(char *s)                            /*;convtoupper*/
  669. {
  670.     /* Convtoupper: convert an entire string to uppercase. */
  671.  
  672.     while (*s) {
  673.         if (islower(*s))
  674.             *s = toupper(*s);
  675.         s++;
  676.     }
  677. }
  678.  
  679. /* merge below text formerly in namelist.c */
  680.  
  681. /* This file contains routines for dealing with namelist/namemap.
  682.    The setup of this map is as follows. We have two arrays: numtostrtable
  683.    and strtonumtable, which are used as hash tables for going from numbers
  684.    to strings and strings to numbers. The hash function from numbers to
  685.    strings is simply taking the number modulo the size of numtostrtable,
  686.    which gives us both the row of numtostrtable where the proper entry for
  687.    a given string should be found, and also where in this row it can be
  688.    found, eliminating the need for searching. The numbers representing the
  689.    strings are assigned sequentially, so we will always be adding a structure
  690.    into a row a the end of the list. This list is kept circularly so as
  691.    to be able to always find the beginning and end of the list quickly,
  692.    and not keep two pointers. When going from strings to numbers, we must
  693.    always search for the string, so the order of the strings in a given row
  694.    of strtonumtable does not matter. Each structure that is put into
  695.    these hash tables holds a string and the corresponding number, and two
  696.    pointers. One pointer points to the next structure in the row of
  697.    numtostrtable in which it lies, and the other points to the next structure
  698.    in the row of strtonumtable in which it lies. Each structure is in two
  699.    linked lists at once, one for each hash table. The grammar symbols and
  700.    predefined pragmas are statically initialized to be in these maps, with
  701.    all pointers set up properly.
  702. */
  703.  
  704. static void nlisthash(int num, int *row, int *links)            /*;nlisthash*/
  705. {
  706.     /* Nlisthash: Hashing function from numbers to strings */
  707.  
  708.     if (num <= 0) printf("nlisthash arg %d negative - chaos\n", num);
  709.     *links = (num - 1) / NAMELISTSIZE;
  710.     *row = (num - 1) % NAMELISTSIZE;
  711. }
  712.  
  713. static int newnode(char *str, int len, int nmhash)                /*;newnode*/
  714. {
  715.     /* Newnode: Allocate storage for a new node; set the fields; insert in 
  716.      * namelist and namemap. The symbol number is returned. Nmhash is either
  717.      * the hashvalue for the given string if already known, or -1 indicating
  718.      * not yet known.
  719.      */
  720.  
  721.     struct namelistmap *node;
  722.     int row, links;
  723.  
  724.     /* Allocate and set fields of node */
  725.     node = (struct namelistmap *)malloc(sizeof(struct namelistmap));
  726.     node->num = ++symcount;
  727.     node->name = malloc((unsigned)(len + 1));
  728.     strcpy(node->name, str);
  729.  
  730.     /* Insert in namelist */
  731.     nlisthash(symcount, &row, &links);
  732.     node->nextlist = numtostrtable[row]->nextlist;
  733.     numtostrtable[row]->nextlist = node;
  734.     numtostrtable[row] = node;
  735.  
  736.     /* Insert in namemap */
  737.     if (nmhash == -1)
  738.         nmhash = strhash(node->name) % NAMEMAPSIZE;
  739.     node->nextmap = strtonumtable[nmhash];
  740.     strtonumtable[nmhash] = node;
  741.  
  742.     return(symcount);
  743. }
  744.  
  745. char *namelist(int num)                                            /*;namelist*/
  746. {
  747.     /* Namelist: Given a symbol number return the corresponding string (the
  748.      * number is assumed to correspond to an entry known to be in the table
  749.      * already)
  750.      */
  751.  
  752.     int row, links;
  753.     struct namelistmap *node;
  754.  
  755.     nlisthash(num, &row, &links);
  756.     node = numtostrtable[row]->nextlist;
  757.     while (links--)
  758.         node = node->nextlist;
  759.     return(node->name);
  760. }
  761.  
  762. int namemap(char *str, int len)                                    /*;namemap*/
  763. {
  764.     /* Namemap: Give the symbol number corresponding to a given string, putting 
  765.      * the string into the structure if not already there. If the string is
  766.      * already known to be in the table, then it is not necessary to give the
  767.      * length.
  768.      */
  769.  
  770.     int nmhash;
  771.     struct namelistmap *node;
  772.     int nnode;
  773.  
  774. #ifdef PDEBUG
  775.     printf("namemap %s\n", str);
  776. #endif
  777.     nmhash = strhash(str) % NAMEMAPSIZE;
  778.     for (node = strtonumtable[nmhash]; node != (struct namelistmap *)0; 
  779.       node = node->nextmap) {
  780.         if (!strcmp(node->name, str)) {
  781. #ifdef PDEBUG
  782.             printf("namemap returns %d\n", node->num);
  783. #endif
  784.             return(node->num);
  785.         }
  786.     }
  787.     nnode = newnode(str, len, nmhash);
  788. #ifdef PDEBUG
  789.     printf("namemap returns (new) %d\n", nnode);
  790. #endif
  791.     return nnode;
  792. }
  793.  
  794. int name_map(char *str)                                            /*;name_map*/
  795. {
  796.     int nmhash;
  797.     struct namelistmap *node;
  798.  
  799.     nmhash = strhash(str) % NAMEMAPSIZE;
  800.     for (node = strtonumtable[nmhash]; node != (struct namelistmap *)0; 
  801.       node = node->nextmap) {
  802.         if (!strcmp(node->name, str))
  803.             return(1);
  804.     }
  805.     return(0);
  806. }
  807.